package net.fruit.mq.client.impl.rocketmq;

import java.util.Properties;

import org.apache.rocketmq.client.impl.producer.DefaultMQProducerImpl;
import org.apache.rocketmq.common.UtilAll;
import org.apache.rocketmq.common.namesrv.TopAddressing;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import net.fruit.mq.client.PropertyKeyConst;
import net.fruit.mq.client.exception.LMQClientException;
import net.fruit.mq.client.impl.authority.SessionCredentials;
import net.fruit.mq.client.impl.util.ClientLoggerUtil;
import net.fruit.mq.client.impl.util.NameAddrUtils;

public abstract class MQClientAbstract {
    // 内网地址服务器
    protected static final String WSADDR_INTERNAL = System.getProperty("com.aliyun.openservices.ons.addr.internal",
            "http://onsaddr-internal.aliyun.com:8080/rocketmq/nsaddr4client-internal");
    // 公网地址服务器
    protected static final String WSADDR_INTERNET = System.getProperty("com.aliyun.openservices.ons.addr.internet",
            "http://onsaddr-internet.aliyun.com/rocketmq/nsaddr4client-internet");
    protected static final long WSADDR_INTERNAL_TIMEOUTMILLS =
            Long.parseLong(System.getProperty("com.aliyun.openservices.ons.addr.internal.timeoutmills", "3000"));
    protected static final long WSADDR_INTERNET_TIMEOUTMILLS =
            Long.parseLong(System.getProperty("com.aliyun.openservices.ons.addr.internet.timeoutmills", "5000"));
    private final static Logger log = ClientLoggerUtil.getClientLogger();
    protected final Properties properties;
    protected final SessionCredentials sessionCredentials = new SessionCredentials();
    protected String nameServerAddr = NameAddrUtils.getNameAdd();

    public MQClientAbstract(Properties properties) {
        this.properties = properties;
        this.sessionCredentials.updateContent(properties);
        // 检测必须的参数
        if (null == this.sessionCredentials.getAccessKey() || "".equals(this.sessionCredentials.getAccessKey())) {
            throw new LMQClientException("please set access key");
        }

        if (null == this.sessionCredentials.getSecretKey() || "".equals(this.sessionCredentials.getSecretKey())) {
            throw new LMQClientException("please set secret key");
        }

        if (null == this.sessionCredentials.getMqChannel()) {
            throw new LMQClientException("please set ons channel");
        }

        // 用户指定了Name Server
        // 私有云模式有可能需要
        String property = this.properties.getProperty(PropertyKeyConst.NAMESRV_ADDR);
        if (property != null) {
            this.nameServerAddr = property;
            return;
        }

        /**
         * 优先级 1、Name Server设置优先级最高 2、其次是地址服务器
         */
        if (null == this.nameServerAddr) {
            String addr = this.fetchNameServerAddr();
            if (null != addr) {
                this.nameServerAddr = addr;
            }
        }
        if (null == this.nameServerAddr) {
            throw new LMQClientException(FAQ.errorMessage("Can not find name server, May be your network problem.", FAQ.FIND_NS_FAILED));
        }
    }

    protected String fetchNameServerAddr() {
        // 用户指定了地址服务器
        String property = this.properties.getProperty(PropertyKeyConst.MQAddr);
        if (property != null) {
            TopAddressing top = new TopAddressing(property);
            return top.fetchNSAddr();
        }

        // 用户未指定，默认访问内网地址服务器
        {
            TopAddressing top = new TopAddressing(WSADDR_INTERNAL);
            String nsAddrs = top.fetchNSAddr(false, WSADDR_INTERNAL_TIMEOUTMILLS);
            if (nsAddrs != null) {
                log.info("connected to internal server, {} success, {}", WSADDR_INTERNAL, nsAddrs);
                return nsAddrs;
            }
        }

        // 用户未指定，然后访问公网地址服务器
        {
            TopAddressing top = new TopAddressing(WSADDR_INTERNET);
            String nsAddrs = top.fetchNSAddr(false, WSADDR_INTERNET_TIMEOUTMILLS);
            if (nsAddrs != null) {
                log.info("connected to internet server, {} success, {}", WSADDR_INTERNET, nsAddrs);
                return nsAddrs;
            }
        }

        return null;
    }

    protected String buildIntanceName() {
        return Integer.toString(UtilAll.getPid())//
                + "#" + this.nameServerAddr.hashCode() //
                + "#" + this.sessionCredentials.getAccessKey().hashCode() + "#" + System.nanoTime();
    }

    public String getNameServerAddr() {
        return nameServerAddr;
    }


    protected void checkMQProducerServiceState(DefaultMQProducerImpl producer) {
        switch (producer.getServiceState()) {
            case CREATE_JUST:
                throw new LMQClientException(
                        FAQ.errorMessage(String.format("You do not have start the producer[" + UtilAll.getPid() + "], %s", producer.getServiceState()),
                                FAQ.SERVICE_STATE_WRONG));
            case SHUTDOWN_ALREADY:
                throw new LMQClientException(FAQ.errorMessage(String.format("Your producer has been shut down, %s", producer.getServiceState()),
                        FAQ.SERVICE_STATE_WRONG));
            case START_FAILED:
                throw new LMQClientException(FAQ.errorMessage(
                        String.format("When you start your service throws an exception, %s", producer.getServiceState()), FAQ.SERVICE_STATE_WRONG));
            case RUNNING:
                break;
            default:
                break;
        }
    }
}
